/*
 *  interpreter.cpp
 *  joosVM
 *
 *  Created by Smári Waage on 11.6.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */

#include "interpreter.h"


typedef void (*function_ptr)(Stack * s);

//List form: id, "name", byte, instruction_size, popoff,pushon,type, function
#define T(identifier, debug, bytecode, size, off_count, on_count, type, method) method,
function_ptr opcodes[Bytecodes::NUM_BYTECODES] = {
BYTECODE_LIST(T)
};
#undef T

Stack* doGarbageCollection(){
	//Look before you leap. 
	//This is an easy place to make the gc, we are not in any call stack and we know where everything is.
	//still have to look for a better place somewhere else.  Also the check is just a check if the there 
	//is less that 10k remaining of the heap, rewind the stack or something.
	//The places that use up space are new and class loading also pushing frames... need a safe point.
	
	
	dout(debug_gc_short,"\n!Doing GC! \n");
	dout(debug_gc,"-----start gc\n",0);
	
#if TRACE_JIT 
	if(Flags::recordTrace){
		TraceRecorder::current->cancelRecord();
	}
#endif
	
	Heap* newH = (Heap*)Heap::startGC();
	
	Pointer** nHP = (Pointer**)malloc(sizeof(Pointer**));
	*nHP = (Pointer*)newH;
	HeapObject* ns = (HeapObject*)Heap::threads[0].stack->forward(nHP);
	Heap::threads[0].stack = (Stack*)ns;
	MethodArea* nma = (MethodArea*)Heap::getMethodArea()->forward(nHP);
	Heap::setMethodArea(nma);
	ns->scan(nHP);
	Heap::endGC(newH,(Heap*)*nHP);
	free(nHP);

	dout(debug_gc,"----- Doing GC ---------------\n\nNow the heap is %i bytes\n\nUsed is %i\n\n",Heap::getHeapSize(),(*nHP - (Pointer*)newH))
	return (Stack*)ns;
}


int Interpreter::executeThread(ThreadContext* context){
	
	Stack* stack = context->stack;
	context->terminate = false;
	context->status = 0;
	byte currentInstr;
	while (!context->terminate) {
		
		if(Heap::shouldWedoGC()){
			stack = doGarbageCollection();
		}
		
		currentInstr = stack->getnextbyte();
		dout(debug_interpreter,"bytecode: %s\n", Bytecodes::LookupBytecode(currentInstr)); 
		
		(*opcodes[currentInstr])(stack);
	}
	
	return context->status;
	
}


int Interpreter::interpret(){
	
	//Setup
	Heap::BuildHeap();
	MethodArea* methodarea = MethodArea::Initialize(200);
	Heap::setMethodArea(methodarea);
	
	ThreadContext* th = &Heap::threads[0];
	th->threadId = 0;
	//ToDo each thread has it's own stack.
	th->stack = Stack::Initialize(0);

	//load the main type/class
	char* mainTypeName = Flags::entryClass;
	JType* mainType = ClassLoader::findType(String::charToString(mainTypeName)); 
	if(mainType == NULL) {printf("%s class not found",mainTypeName); return 1;}
	JMethod* main = mainType->lookupMethod(String::charToString("main([Ljava/lang/String;)V"));
	if(main == NULL){printf("no main found in %s ",mainTypeName); return 1;}
	
	TaggedArray* mainArgs = TaggedArray::Initalize(main->getMaxLocals());
	if(Flags::entryClassArgc > 0){
		mainArgs->setRef(0,String::charToString(Flags::entryClassArgs[0]));
	}//FIX!!! make the string array
	
	//push the first frame on the stack
	th->stack->pushOnFrame(main,mainArgs);// activateFrame(main ,false);
	
		
	return executeThread(th);
}


